package io.kiki.stack.netty.invoker;


import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Setter
@Getter
public class RequestContext {
    // ~~~ invoke context keys of client side
    public final static String CLIENT_LOCAL_IP = "client.local.ip";
    public final static String CLIENT_LOCAL_PORT = "client.local.port";
    public final static String CLIENT_REMOTE_IP = "client.remote.ip";
    public final static String CLIENT_REMOTE_PORT = "client.remote.port";
    /**
     * time consumed during Channel creating, this is a timespan
     */
    public final static String CLIENT_CONN_CREATETIME = "client.conn.createtime";
    public final static String CLIENT_CONN_CREATE_START_IN_NANO = "client.conn.create.start.nano";
    public final static String CLIENT_CONN_CREATE_END_IN_NANO = "client.conn.create.end.nano";

    // ~~~ invoke context keys of server side
    public final static String SERVER_LOCAL_IP = "server.local.ip";
    public final static String SERVER_LOCAL_PORT = "server.local.port";
    public final static String SERVER_REMOTE_IP = "server.remote.ip";
    public final static String SERVER_REMOTE_PORT = "server.remote.port";

    // ~~~ invoke context keys of  client and server side
    public final static String _INVOKE_REQUEST_ID = "invoke.request.id";
    /**
     * time consumed start from the time when request arrive, to the time when request be processed, this is a timespan
     */
    public final static String _PROCESS_WAIT_TIME = "invoke.wait.time";
    /**
     * time request arrived in nano seconds , collected by System.nanoTime()
     */
    public final static String _PROCESS_ARRIVE_HEADER_IN_NANO = "invoke.request.arrive.header.in.nano";
    public final static String _PROCESS_ARRIVE_BODY_IN_NANO = "invoke.request.arrive.body.in.nano";

    /**
     * time before send request to user thread in nano seconds , collected by System.nanoTime()
     */
    public final static String _PROCESS_BEFORE_DISPATCH_IN_NANO = "invoke.before.dispatch.in.nano";

    /**
     * time before send request to user thread in nano seconds , collected by System.nanoTime()
     */
    public final static String _PROCESS_START_PROCESS_IN_NANO = "invoke.start.process.in.nano";


    public final static String _CRC_SWITCH = "invoke.crc.switch";

    /**
     * time before send request to net in nano seconds , collected by System.nanoTime()
     **/
    public final static String _PROCESS_CLIENT_BEFORE_SEND = "invoke.client.before.send";
    /**
     * time after send request to net in nano seconds , collected by System.nanoTime()
     **/
    public final static String _PROCESS_CLIENT_AFTER_SEND = "invoke.client.after.send";
    /**
     * time after receive response from server in nano seconds , collected by System.nanoTime()
     **/
    public final static String _PROCESS_CLIENT_RECEIVED = "invoke.client.received";

    // ~~~ constants
    public final static int INITIAL_SIZE = 8;
    /**
     * context
     */
    private final ConcurrentHashMap<String, Object> map;


    public RequestContext() {

        this.map = new ConcurrentHashMap<String, Object>(INITIAL_SIZE);
    }

    public void put(String key, Object value) {
        this.map.put(key, value);
    }

    public void putIfAbsent(String key, Object value) {
        this.map.putIfAbsent(key, value);
    }


    public <T> T get(String key) {
        return (T) this.map.get(key);
    }


    public <T> T get(String key, T defaultIfNotFound) {
        return this.map.get(key) != null ? (T) this.map.get(key) : defaultIfNotFound;
    }


    public void clear() {

        this.map.clear();
    }


}
